---
description: Learn how to self host Triplit using Docker, and how to deploy it to a cloud provider with Docker or Git.
---

import { Callout } from 'nextra/components';

# Self-hosting Triplit

To enable sync, you need to run a Triplit server. The server is a Node.js application that talks to various Triplit clients over WebSockets and HTTP.

You have several options for running the server:

- A local [development server](/local-development)
- Use [Docker](#docker) and a cloud provider that supports container deployments
- Use a [one-click deploy](#one-click-deploy) to a cloud provider that is integrated with Triplit.
- Build [a custom server](#building-a-custom-server) and use a cloud provider that supports Git-based deploys

<Callout type="warning" emoji="⚠️">

The guide on this page is specifically for standalone, self-hosted deployments that are not compatible with the Triplit Cloud Dashboard.

We recommend that you instead follow [this guide](/triplit-cloud/self-hosted-deployments) for self-hosting your Triplit Server while still making it accessible and configurable via the Triplit Dashboard.

</Callout>

## Docker

Each release of the server is [published as a Docker image](https://hub.docker.com/r/aspencloud/triplit-server/tags). You can deploy the server to a cloud provider like [fly.io](https://fly.io/docs/languages-and-frameworks/dockerfile/), [DigitalOcean](https://docs.digitalocean.com/products/app-platform/how-to/deploy-from-container-images/), or AWS. You'll also want to setup a volume to persist the database.

The docker file starts a node server on port 8080, and you can pass in the following environment variables to configure the server:

- `NODE_OPTIONS` - Node.js options for the server (e.g. `--max-old-space-size=4096`)

## One-click deploy

Triplit is integrated with [Railway](https://railway.app/), a cloud provider that supports one-click deploys. Read about how to deploy a Triplit server using Railway in our [Triplit Cloud guide](/triplit-cloud/self-hosted-deployments).

We plan on adding support for more cloud providers in the future. If you have a favorite cloud provider that you'd like to see integrated with Triplit, let us know by [joining our Discord](https://discord.gg/q89sGWHqQ5).

## Building a custom server

The server is published as an NPM package, and you can install it by running:

```bash copy
npm install @triplit/server
```

The server also contains the remote Triplit database, which will persist data synced from your clients. The server supports different storage adapters, such as SQLite. Using the `createServer` function, you can create and configure a new server instance:

```js filename="run.js" copy
import { createServe, createTriplitStorageProvider } from '@triplit/server';

const port = +(process.env.PORT || 8080);

const startServer = createServer({
  storage: await createTriplitStorageProvider('sqlite'),
  verboseLogs: true,
});

const dbServer = startServer(port);

console.log('running on port', port);
process.on('SIGINT', function () {
  dbServer.close(() => {
    console.log('Shutting down server... ');
    process.exit();
  });
});
```

You can now deploy the server to a cloud provider that supports Git deploys, like [Vercel](https://vercel.com/docs/git), [Netlify](https://docs.netlify.com/configure-builds/get-started/), or [Render](https://docs.render.com/deploys).

### Storage

Triplit is designed to support any storage that can implement a key value store. You may specify the storage adapter you want to use by setting the `storage` option. Triplit provides some default configurations of our storage adapters, which you can use by setting the `storage` option to the appropriate string value for the adapter. These include:

- `memory` (default) - See `memory-btree`
- `sqlite` - An SQLite storage adapter, which requires the installation of the [`better-sqlite3` package](https://github.com/WiseLibs/better-sqlite3)
- `lmdb` - An LMDB storage adapter, which requires the installation of the [`lmdb` package](https://github.com/kriszyp/lmdb-js)

<Callout type="warning" emoji="⚠️">
  In-memory storage adapters are not durable and are not recommended for
  production use.
</Callout>

Typically this will use your `LOCAL_DATABASE_URL` environment variable so you'll want to make sure that's set.

You can also pass in an instance of an adapter or a function that returns an instance of an adapter.

```typescript
function createAdapter() {
  return new MyCustomAdapter();
}

const startServer = createServer({
  storage: createAdapter,
});
```

## Health checks

The server exposes a health check endpoint at `/healthcheck`. This endpoint will return a 200 status code if the server is running and healthy.

## Secrets

There are a few secrets that you need to provide to the server to enable certain features. **If you are planning on using the Triplit Dashboard, you will need to set `JWT_SECRET` to the global Triplit public RSA key associated with your project.** Read the [Triplit Cloud guide](/triplit-cloud/self-hosted-deployments#configuration) for more information.

### `JWT_SECRET`

The server uses JWT tokens to authenticate clients, and you need to provide a symmetric secret or public key to verify these tokens that it receives. The `JWT_SECRET` environment variable should be assigned to this validation secret. Triplit supports both symmetric (HS256) and asymmetric (RS256) encryption algorithms for JWTs. You will need to generate client tokens signed with the appropriate algorithm.

You can generate tokens with the `jsonwebtoken` package (e.g. if you wanted to use asymmetric encryption) :

```typescript copy
import jwt from 'jsonwebtoken';

const anonKey = jwt.sign(
  {
    'x-triplit-token-type': 'anon',
  },
  process.env.PUBLIC_KEY,
  { algorithm: 'RS256' }
);

const serviceKey = jwt.sign(
  {
    'x-triplit-token-type': 'secret',
  },
  process.env.PUBLIC_KEY,
  { algorithm: 'RS256' }
);
```

For more complicated authentication schemes, refer to our [authentication guide](/auth).

### `LOCAL_DATABASE_URL` (required for durable storage)

An absolute path on the server's file system to a directory where the server will store any database files. This is required for durable storage options: `lmdb`, and `sqlite`.

### `EXTERNAL_JWT_SECRET` (optional)

<Callout type="warning" emoji="⚠️">
  If you plan to connect your self-hosted Triplit server to the Triplit
  Dashboard and use JWTs for authentication and permission within Triplit,
  EXTERNAL_JWT_SECRET should only be set on your Triplit Dashboard. Ensure the
  env var is NOT included wherever you deployed your Docker image. Otherwise,
  you may encounter errors related to invalid JWTs and JWT signatures.
</Callout>

If you want your server to support JWTs signed by a second issuer, you can also set `EXTERNAL_JWT_SECRET` to that signing secret (or public key). For the server to recognize a JWT as "external", it must **not** have the `x-triplit-token-type` claim or if that claim is set, it must **not** have the value of `anon` or `secret`. Those specific combinations of claims are reserved for "internal" JWTs, e.g. the special `anon` and `secret` tokens.

### `CLAIMS_PATH` (optional)

If you are using custom JWTs with nested Triplit-related claims, you can set the `CLAIMS_PATH` environment variable. The server will read the claims at the path specified by `CLAIMS_PATH`. Read the [authentication guide](/auth) for more information.

### `SENTRY_DSN` (optional)

If you want to log errors to Sentry, you can set the `SENTRY_DSN` environment variable. The server will automatically log errors to Sentry.

### `VERBOSE_LOGS` (optional)

If you want to log all incoming and outgoing messages and requests, you can set the `VERBOSE_LOGS` environment variable. This can be useful for debugging.
